package com.zh.freechat.domain.user.service;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zh.freechat.domain.user.entity.ApplyFriend;
import com.zh.freechat.domain.user.entity.ChatUser;
import com.zh.freechat.domain.user.entity.UserContacts;
import com.zh.freechat.domain.user.entity.UserRelationBlack;
import com.zh.freechat.domain.user.repository.ApplyFriendRecordRepository;
import com.zh.freechat.domain.user.repository.UserContactRepository;
import com.zh.freechat.domain.user.repository.UserRepository;
import com.zh.webcommon.common.exception.NotFoundException;
import com.zh.webcommon.common.exception.ServiceException;
import com.zh.webcommon.common.exception.errorcode.BizError;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.zh.freechat.common.CustomConst.friend_relation_agreed;
import static com.zh.freechat.common.CustomConst.friend_relation_refuse;
import static com.zh.freechat.common.CustomConst.friend_relation_unagreed;
import static com.zh.webcommon.CommonConst.GSON;


/**
 * 用户联系人service
 *
 * @author ZH
 * @date 10:47 2021/7/16
 */
@Slf4j
@AllArgsConstructor
@Service
public class UserContactsService {
    private final UserRepository userRepository;
    private final UserContactRepository userContactRepository;
    private final ApplyFriendRecordRepository applyFriendRecordRepository;

    private static final ChatUser emptyUser = new ChatUser();

    /**
     * userId申请添加toUserId为好友
     *
     * @param userId   用户
     * @param toUserId 好友
     * @param remark   申请的备注
     */
    @Transactional
    public void applyAdd(String userId, String toUserId, String remark) {
        if (userId.equals(toUserId)) {
            return;
        }
        var applyId = checkApply(userId, toUserId);
        if (applyId != null) {
            applyFriendRecordRepository.closeOne(applyId);
        }
        //userId 申请添加 toUserId
        var applyRecord = new ApplyFriend(userId, toUserId, remark);
        applyFriendRecordRepository.insert(applyRecord);
    }

    /**
     * 检查申请是否合法
     *
     * @param applyUserId
     * @param toUserId
     * @return 返回最近的添加申请ID，没有则返回null
     */
    @Nullable
    private Long checkApply(String applyUserId, String toUserId) {
        if (Objects.equals(applyUserId, toUserId)) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "不能添加自己为好友");
        }

        //被拉黑不能申请
        if (isBlacklist(applyUserId, toUserId)) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "该用户已隐身");
        }

        //applyUserId和toUserId是不是好友
        if (isFriend(applyUserId, toUserId)) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "你们已经是好友了，不能再添加啦");
        }

        //未申请过：可以申请
        //申请未被同意：可以申请
        //申请已被同意，是好友：不能申请
        //申请已被同意，不是好友：可以申请：
        //申请被拒绝过：可以申请：但是今天不能申请
        ApplyFriend applyRecord = applyFriendRecordRepository.getActiveApplyRecord(applyUserId, toUserId);
        if (applyRecord != null && applyRecord.getStatus() == friend_relation_refuse && applyRecord.getCreateTime().toLocalDate().isEqual(LocalDate.now())) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "你的好友申请已被拒绝，无法申请");
        }

        return applyRecord == null ? null : applyRecord.getId();
    }

    public void clearApplyById(Long id) {
        applyFriendRecordRepository.deleteById(id);
    }

    public void clearAppliesByUser(String userId) {
        var query = new QueryWrapper<ApplyFriend>().eq("user_id", userId);
        applyFriendRecordRepository.delete(query);
    }

    public void removeContact(String userId, String friendId) {
        //判断是不是好友，如果是好友才能删除
        if (!isFriend(userId, friendId)) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "不存在好友关系，无法删除操作");
        }
        userContactRepository.bothRemoveContact(userId, friendId);
    }

    /**
     * queryUserId是不是在userId的黑名单上
     *
     * @param queryUserId 要查询的用户
     * @param userId      用户
     * @return boolean
     */
    public boolean isBlacklist(String queryUserId, String userId) {
        return userContactRepository.isBlacklist(queryUserId, userId);
    }

    /**
     * userId 同意添加好友
     *
     * @param id     apply记录的ID
     * @param userId 被添加的userId
     */
    @Transactional
    public void agreedFriend(Long id, String userId) {
        //applyUserId 是不是申请了添加 userId
        var applyRecord = applyFriendRecordRepository.selectById(id);
        if (applyRecord == null) {
            throw new NotFoundException("找不到id=" + id + "的好友申请记录");
        }

        if (!Objects.equals(applyRecord.getUserId(), userId) || applyRecord.getStatus() != friend_relation_unagreed) {
            log.error("好友添加申请的userId匹配不对，拒绝操作。 toUserId={}, apply={}", userId, GSON.toJson(applyRecord));
            throw new ServiceException(BizError.DEFAULT_ERROR, "不存在此好友添加申请，拒绝操作");
        }

        //申请好友记录更新为已同意
        applyRecord.setStatus(friend_relation_agreed);
        applyFriendRecordRepository.updateById(applyRecord);

        //联系人表中添加好友关系
        //userId 添加 ToUserId 为好友
        userContactRepository.bothAddContact(applyRecord.getApplyUserId(), userId);

    }

    /**
     * userId 拒绝添加好友
     *
     * @param id
     * @param userId
     */
    public void refuseFriend(Long id, String userId) {
        //applyUserId 是不是申请了添加 userId
        var applyRecord = applyFriendRecordRepository.selectById(id);
        if (applyRecord == null) {
            throw new NotFoundException("找不到id=" + id + "的好友申请记录");
        }
        if (!Objects.equals(applyRecord.getUserId(), userId) || applyRecord.getStatus() != friend_relation_unagreed) {
            throw new ServiceException(BizError.DEFAULT_ERROR, "不存在此好友添加申请，拒绝操作");
        }

        //申请好友记录更新为已拒绝
        applyRecord.setStatus(friend_relation_refuse);
        applyFriendRecordRepository.updateById(applyRecord);
    }

    public void addBlack(String userId, String toUserId) {
        UserRelationBlack black = new UserRelationBlack(userId, toUserId);
        userContactRepository.addBlack(black);
    }

    public void removeBlack(String userId, String toUserId) {
        UserRelationBlack black = new UserRelationBlack(userId, toUserId);
        userContactRepository.removeBlack(black);
    }

    /**
     * 获取用户的联系人列表
     * 其中包含黑名单列表
     *
     * @param userId
     * @return
     */
    public UserContacts contactsByUserId(String userId) {
        UserContacts contacts = userContactRepository.findContacts(userId);
        contacts.getFriends().forEach(friend -> {
            var chatUser = userRepository.selectById(friend.getFriendId(userId));
            friend.setChatUser(chatUser != null ? chatUser : emptyUser);
        });
        return contacts;
    }

    public List<ApplyFriend> findUnsettledApplyRecordList(String userId) {
        List<ApplyFriend> applyList = applyFriendRecordRepository.findUnsettledApplyRecordList(userId);
        if (applyList == null || applyList.isEmpty())
            return Collections.emptyList();

        applyList.forEach(e -> {
            var chatUser = userRepository.selectById(e.getApplyUserId());
            e.setApplyUser(chatUser != null ? chatUser : emptyUser);
        });
        return applyList;
    }

    /**
     * user和chatter是不是好友关系
     *
     * @param userId
     * @param chatUserId
     * @return
     */
    public boolean isFriend(String userId, String chatUserId) {
        return userContactRepository.isFriendRelation(userId, chatUserId);
    }

    /**
     * 过滤为好友的chatters ID集合
     *
     * @param userId
     * @param chatters
     * @return
     */
    public Set<String> fetchContacts(String userId, List<String> chatters) {
        return chatters.stream()
                .filter(e -> userContactRepository.isFriendRelation(e, userId))
                .collect(Collectors.toSet());
    }

    /**
     * 过滤为陌生人的chatters ID集合
     *
     * @param userId
     * @param chatters
     * @return
     */
    public Set<String> fetchStrangers(String userId, Collection<String> chatters) {
        return chatters.stream()
                .filter(e -> !userContactRepository.isFriendRelation(e, userId))
                .collect(Collectors.toSet());
    }

}
